package com.apobates.forum.grief.concurrent;

import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 * 组合对象的契约接口
 * @param <ID> 组合对象查询参数的类型
 * @param <T> 组合对象类型
 * @param <V> 值对象的类型
 * @param <R> 值对象的目标对象类型
 */
public interface CombineCollectionPromise<ID, T, V, R> {
    /**
     * 从目标对象中获取查询参数
     * @param entity 目标对象
     * @return
     */
    ID param(R entity);

    /**
     * 根据查询参数获取组合对象流
     * @param idParams 查询参数
     * @return
     */
    CompletableFuture<Stream<T>> query(Set<ID> idParams);

    /**
     * 组合对象到值对象的映射函数
     * @return
     */
    BiFunction<Stream<V>, Stream<T>, Stream<V>> mapper();

    static class Builder<ID,T,V,R> {
        private Function<R,ID> param;
        private BiFunction<Stream<V>, Stream<T>, Stream<V>> mapper;
        private Function<Set<ID>, Supplier<Stream<T>>> source;

        private Builder() {
        }

        public static<ID,T,V,R> Builder<ID,T,V,R> defaultIns(){
            return new Builder<>();
        }

        public Builder<ID,T,V,R> param(Function<R,ID> paramMapper){
            this.param = paramMapper;
            return this;
        }

        public Builder<ID,T,V,R> source(Function<Set<ID>, Supplier<Stream<T>>> source){
            this.source = source;
            return this;
        }

        public Builder<ID,T,V,R> mapper(String attrName, Function<T,ID> keyMapper, Function<V,ID> valueMapper){
            CombineCollectionPromiseMapper<ID,T,V> tmp = new CombineCollectionPromiseMapper<ID,T,V>(){

                @Override
                public Function<T,ID> keyMapper() {
                    return keyMapper;
                }

                @Override
                public String attrName() {
                    return attrName;
                }

                @Override
                public Function<V,ID> valMapper() {
                    return valueMapper;
                }
            };
            this.mapper = tmp.mapper();
            return this;
        }

        public CombineCollectionPromise<ID,T,V,R> build() {
            return new CombineCollectionPromise<>(){
                @Override
                public ID param(R entity) {
                    return param.apply(entity);
                }

                @Override
                public CompletableFuture<Stream<T>> query(Set<ID> idParams) {
                    return CompletableFuture.supplyAsync(()->source.apply(idParams).get());
                }

                @Override
                public BiFunction<Stream<V>, Stream<T>, Stream<V>> mapper() {
                    return mapper;
                }
            };
        }
    }
}
